package com.sxj.corejava.util;

import java.io.*;

/**
 * @author 石小俊
 * @date 2024年05月16日 19:48
 */
public class FileUtil {

    /**
     * 拷贝文件,将指定文件src的内容拷贝到指定文件target中
     * @param src    源文件
     * @param target 目标文件
     */
    public static void copyFile(File src, File target) {
        try (
                InputStream in = new FileInputStream(src);
                OutputStream out = new FileOutputStream(target);
        ) {
            byte[] b = new byte[1024];
            int i = -1;
            // 写入文件时,如果文件不存在,会自动创建对应文件
            while ((i = in.read(b)) != -1) {
                out.write(b, 0, i);
            }
            System.out.println("提示:文件拷贝成功!");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 拷贝文件
     * @param src    源文件
     * @param target 目标文件
     */
    public static void copyFile(String src, String target) {
        copyFile(new File(src), new File(target));
    }

    /**
     * 将一个目录中所有的文件拷贝到指定目录中
     * 目标目录通过代码自动创建
     * @param src    源目录
     * @param target 目标目录
     */
    public static void copyDirectory(String src, String target) {
        // 获取源目录中所有资源
        File srcFile = new File(src);
        File[] files = srcFile.listFiles();

        // 创建目标目录
        File targetFile = new File(target);
        targetFile.mkdirs();
        for (File file : files) {
            // 每遍历一个文件,均将其拷贝到指定目录中
            // 目标文件为:目标目录+分隔符+需要拷贝的文件名
            copyFile(file, new File(target + File.separator + file.getName()));
        }
    }

    /**
     * 将一个目录中的文件与子目录递归拷贝到一个指定的目录中
     * 涉及的所有目录均通过代码自动创建
     * @param src
     * @param target
     */
    public static void recursiveCopy(String src, String target) {
        // 获取源目录中所有资源
        File srcFile = new File(src);
        File[] files = srcFile.listFiles();

        // 创建目标目录
        File targetFile = new File(target);
        targetFile.mkdirs();

        // 遍历所有资源
        for (File file : files) {
            // 如果是目录
            if (file.isDirectory()) {
                // 递归操作
                // 源目录:当前的子目录的绝对路径
                // 目标目录:当前目标目标+分隔符+需要拷贝的子目录名
                recursiveCopy(file.getAbsolutePath(), target + File.separator + file.getName());
            } else {
                // 如果是文件,直接拷贝
                copyFile(file, new File(target, file.getName()));
            }
        }
    }

    /**
     * 拆分文件,将一个文件按照指定大小拆分成多个文件,每一个文件名字为:原名字_index,index从1开始,每次自增1
     * 一个输入流,多个输出流,在输出时,每循环一次,输出一个子文件
     * @param path   文件路径
     * @param length 分割的文件大小
     */
    public static void splitFile(String path, int length) {
        FileInputStream in = null;
        FileOutputStream out = null;
        try {
            in = new FileInputStream(path);
            // 设置每次读取的字节数
            byte[] b = new byte[length];
            int i = -1;
            int index = 1;
            while ((i = in.read(b)) != -1) {
                // 每次读取生成一个新的文件,对应一个新的输出流
                out = new FileOutputStream(path + "_" + index++);
                out.write(b, 0, i);
                // 输出流完成之后,将当前的输出流关闭
                out.close();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 合并文件,将之前拆分的文件合并为一个文件,将子文件的_index部分删除作为文件名
     * 传入的参数是第一个文件,合并时将所有与该文件名字格式相同的文件进行合并
     * 合并的所有文件均为均为:文件名_索引号
     * 一个输出流,多个输入流
     * @param path 传入的是第一个文件
     */
    public static void mergeFile(String path) {
        // 将传入的参数中_后面的部分去除
        path = path.substring(0, path.lastIndexOf("_"));
        try {
            // 指定一个输出流
            FileOutputStream out = new FileOutputStream(path);
            // 定义所有合并的子文件的后缀数字
            int index = 1;
            File file = null;
            // 判断需要合并的文件是否存在
            while ((file = new File(path + "_" + index++)).exists()) {
                // 定义输入流
                FileInputStream in = new FileInputStream(file);
                copyStream(in, out);
                // 关闭当前开启的输入流
                in.close();
            }
            System.out.println(path + "合并成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 合并文件,将之前拆分的文件合并为一个文件,将子文件的_index部分删除作为文件名
     * 传入的参数是第一个文件,合并时将所有与该文件名字格式相同的文件进行合并
     * 合并的所有文件均为均为:文件名_索引号
     * 一个输出流,多个输入流
     * @param firstFile 传入的是第一个文件对象
     */
    public static void mergeFile(File firstFile) {
        String path = firstFile.getAbsolutePath();
        // 将传入的参数中_后面的部分去除
        path = path.substring(0, path.lastIndexOf("_"));
        try {
            // 指定一个输出流
            FileOutputStream out = new FileOutputStream(path);
            // 定义所有合并的子文件的后缀数字
            int index = 1;
            File file = null;
            // 判断需要合并的文件是否存在
            while ((file = new File(path + "_" + index++)).exists()) {
                // 定义输入流
                FileInputStream in = new FileInputStream(file);
                copyStream(in, out);
                // 关闭当前开启的输入流
                in.close();
            }
            System.out.println(path + "合并成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void copyStream(FileInputStream in, FileOutputStream out) throws IOException {
        try {
            byte[] b = new byte[1024 * 1024];
            int i = -1;
            while ((i = in.read(b)) != -1) {
                out.write(b, 0, i);
            }
        } catch (IOException e) {
            e.printStackTrace();
            throw e;
        }
    }


    /**
     * 文件加密
     * 读取文件中的每一个字节,根据指定的密码对其进行加密,加密后的文件添加.sec后缀
     * 按字节读取,每个字节都通过异或操作进行加密
     * @param file
     * @param password
     */
    public static void encoded(File file, int password) {

    }

    /**
     * 文件解密
     * 读取加密后的文件中的每一个字节,根据指定的密码对其进行解密,解密后的文件去除.sec后缀
     * 按字节读取,每个字节都通过异或操作进行解密
     * @param file
     * @param password
     */
    public static void decoded(File file, int password) {

    }
}
